package com.itlaobing.reflection.loader;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Logger;

public class ItlaobingClassLoader extends ClassLoader {

    private static Logger logger = Logger.getLogger( ItlaobingClassLoader.class.getName() );

    private String base ; // 从那个目录开始寻找

    public ItlaobingClassLoader(String base) {
        super();
        this.base = base;
    }

    /**
     * 通过一个类的全限定名称来读取该类对应的字节码数据，
     * 随后将字节码数据转化为 运行时数据结构，
     * 最后返回与相应的 运行时数据结构 对应的 java.lang.Class实例
     * @param name 需要加载的类的 全限定名称
     * @return 返回与相应的 运行时数据结构 对应的 java.lang.Class实例
     * @throws ClassNotFoundException 如果在指定目录中找不到指定的类则抛出ClassNotFoundException
     */
    @Override
    protected Class<?> findClass( final String name ) throws ClassNotFoundException {
        Class<?> c = null ;

        // 由参数传入的 name 表示某个类的【全限定名称】
        logger.info( name );

        // 替换全限定名称中的 圆点 为 斜杠 ，并在末尾追加 .class 后缀
        String path = name.replace( '.' , '/' ) + ".class" ;
        logger.info( path );
        // 在 包对应的路径之前 加上 基本路径 (即从该目录开始搜索包和类)
        String pathname = base + "/" + path ;
        logger.info( pathname );

        byte[] bytes ;
        try {
            // 创建一个可以从 从 指定的目录下 的 指定的 字节码文件 读取数据的字节输入流
            InputStream in = new FileInputStream( pathname );
            // 读取字节码文件中的所有数据到一个字节数组中 ( 将字节码数据全部放到一个字节数组中 )
            bytes = in.readAllBytes();
            logger.info( "bytes : " + bytes.length );
            in.close();
        } catch (IOException e) {
            throw new IllegalStateException( "读取字节码文件时发生错误" , e );
        }

        // 将 字节码数据 转换为方法区中的 运行时数据结构 ，并返回与之对应的 java.lang.Class实例
        c = this.defineClass( name , bytes , 0 , bytes.length );
        logger.info( c.toString() );

        return c ;
    }
}
